﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Web;
using System.IO;
using System.Drawing.Imaging;
using log4net;
using System.Drawing.Drawing2D;
using BetterImageProcessorQuantization;

namespace Jalal.Library.Utility
{
    public class ImageResizer
    {
        public static string CheckImageMissing(string imageUrl, string noImagePath)
        {
            FileInfo imageFile = new FileInfo(HttpContext.Current.Server.MapPath(imageUrl));
            if (imageFile.Exists)
            {
                //System.Drawing.Size originalImageDimension = ImageResizer.GetImageDimension(imageUrl);
                return imageUrl;
            }
            return noImagePath;
        }

        public static string RandomizeImageFileName(string plainName)
        {
            if (string.IsNullOrEmpty(plainName))
                throw new ArgumentNullException("plainName is not provided");

            int indexOfDot = plainName.LastIndexOf('.');
            string extension = plainName.Substring(indexOfDot);

            if (plainName.Contains("_"))
            {
                int indexOfGuid = plainName.LastIndexOf('_');

                if (indexOfGuid > 0 && indexOfGuid < plainName.Length)
                {
                    string actualName = plainName.Substring(0, indexOfGuid);
                    return actualName + "_" + Guid.NewGuid().ToString().Replace("-", "") + extension;
                }
            }
            else
            {
                if (indexOfDot > 0 && indexOfDot < plainName.Length)
                {
                    string actualName = plainName.Substring(0, indexOfDot);
                    return actualName + "_" + Guid.NewGuid().ToString().Replace("-", "") + extension;
                }
            }

            return null;
        }

        public static string CreateThumbnail(string parentImageFilePath, string outputImageFilePath, int width, int height, bool addSufix, string sufix)
        {
            // Trying to locate the original image file
            string parentImageFileFullPath = HttpContext.Current.Server.MapPath(parentImageFilePath);

            if (File.Exists(parentImageFileFullPath))
            {
                if (string.IsNullOrEmpty(sufix))
                    sufix = "_thumb";

                // Adding the sufix to the filename
                if (addSufix)
                    outputImageFilePath = (outputImageFilePath.Insert(outputImageFilePath.IndexOf('.'), sufix));

                // Deleting if the file already exists.
                if (File.Exists(outputImageFilePath))
                    FileAccessUtility.DeleteFile(outputImageFilePath);

                // Loading the image from image file
                using (Image parentImage = Image.FromFile(parentImageFileFullPath))
                {
                    // Creating the thumbnail for optimization
                    Image thumbnail = new Bitmap(width, height);
                    Graphics graphic = Graphics.FromImage(thumbnail);

                    graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
                    graphic.SmoothingMode = SmoothingMode.HighQuality;
                    graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
                    graphic.CompositingQuality = CompositingQuality.HighQuality;

                    graphic.DrawImage(parentImage, 0, 0, width, height);

                    if (parentImageFilePath.ToLower().EndsWith(".gif"))
                    {
                        using (thumbnail)
                        {
                            OctreeQuantizer quantizer = new OctreeQuantizer(255, 8);
                            using (Bitmap quantized = quantizer.Quantize(thumbnail))
                            {
                                using (FileStream outputStream = new FileStream(HttpContext.Current.Server.MapPath(outputImageFilePath), FileMode.Create))
                                {
                                    quantized.Save(outputStream, ImageFormat.Gif);
                                }
                            }
                        }
                    }
                    else if (parentImageFilePath.ToLower().EndsWith(".jpg"))
                    {
                        ImageCodecInfo[] info = ImageCodecInfo.GetImageEncoders();
                        EncoderParameters encoderParameters;
                        encoderParameters = new EncoderParameters(1);
                        encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
                        using (FileStream outputStream = new FileStream(HttpContext.Current.Server.MapPath(outputImageFilePath), FileMode.Create))
                        {
                            thumbnail.Save(outputStream, info[1], encoderParameters);
                        }
                    }
                    else
                    {
                        Image thumbnailImage = parentImage.GetThumbnailImage(width, height, null, IntPtr.Zero);
                        thumbnailImage.Save(HttpContext.Current.Server.MapPath(outputImageFilePath), parentImage.RawFormat);
                    }
                }
                return outputImageFilePath;
            }
            else
                return null;
        }

        /// <summary>
        /// Creates a thumbnail image from another image with the width 
        /// specified. Helpful in case of creating a different sized thumbnail 
        /// image from the original image. This method overwrites if the file
        /// already exists.
        /// </summary>
        /// <param name="parentImageFilePath">Path of the original image. This is relative path from site root</param>
        /// <param name="outputImageFilePath">Path of the output image where to create the thumbnail. This includes the output filename.</param>
        /// <param name="width">Desired width of the thumbnail image</param>
        /// <param name="addSufix">If true, an extension is added to differentiate from the original image</param>
        /// <param name="sufix">The sufix to be be added in output filename, if not supplied, _thumb will be used.</param>
        /// <returns>True if the thumbnail is successfuly created, false otherwise</returns>
        public static string CreateThumbnail(string parentImageFilePath, string outputImageFilePath, int width, bool addSufix, string sufix)
        {
            // Trying to locate the original image file
            string parentImageFileFullPath = HttpContext.Current.Server.MapPath(parentImageFilePath);

            if (File.Exists(parentImageFileFullPath))
            {
                if (string.IsNullOrEmpty(sufix))
                    sufix = "_thumb";

                // Adding the sufix to the filename
                if (addSufix)
                    outputImageFilePath = outputImageFilePath.Insert(outputImageFilePath.IndexOf('.'), sufix);

                // Deleting if the file already exists.
                if (File.Exists(outputImageFilePath))
                    FileAccessUtility.DeleteFile(outputImageFilePath);

                // Loading the image from image file
                using (Image parentImage = Image.FromFile(parentImageFileFullPath))
                {
                    int height = (int)(parentImage.Height * ((double)width / (double)parentImage.Width));

                    // Creating the thumbnail and saving it 
                    Image thumbnail = new Bitmap(width, height);
                    Graphics graphic = Graphics.FromImage(thumbnail);

                    graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
                    graphic.SmoothingMode = SmoothingMode.HighQuality;
                    graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
                    graphic.CompositingQuality = CompositingQuality.HighQuality;

                    graphic.DrawImage(parentImage, 0, 0, width, height);

                    if (parentImageFilePath.ToLower().EndsWith(".gif"))
                    {
                        using (thumbnail)
                        {
                            OctreeQuantizer quantizer = new OctreeQuantizer(255, 8);
                            using (Bitmap quantized = quantizer.Quantize(thumbnail))
                            {
                                using (FileStream outputStream = new FileStream(HttpContext.Current.Server.MapPath(outputImageFilePath), FileMode.Create))
                                {
                                    quantized.Save(outputStream, ImageFormat.Gif);
                                }
                            }
                        }
                    }
                    else if (parentImageFilePath.ToLower().EndsWith(".jpg"))
                    {
                        ImageCodecInfo[] info = ImageCodecInfo.GetImageEncoders();
                        EncoderParameters encoderParameters;
                        encoderParameters = new EncoderParameters(1);
                        encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
                        using (FileStream outputStream = new FileStream(HttpContext.Current.Server.MapPath(outputImageFilePath), FileMode.Create))
                        {
                            thumbnail.Save(outputStream, info[1], encoderParameters);
                        }
                    }
                    else
                    {
                        // Dynamically calculating the height of the thumbnail image according to ratio
                        Image thumbnailImage = parentImage.GetThumbnailImage(width, height, null, IntPtr.Zero);
                        thumbnailImage.Save(HttpContext.Current.Server.MapPath(outputImageFilePath), parentImage.RawFormat);
                    }
                }
                return outputImageFilePath;
            }
            else
                return null;
        }

        /// <summary>
        /// Creates a thumbnail image from another image with the width and height
        /// specified. Helpful in case of creating a different sized thumbnail 
        /// image from the original image.
        /// </summary>
        /// <param name="parentImageFilePath">Path of the original image. This is relative path from site root</param>
        /// <param name="outputImageFilePath">Path of the output image where to create the thumbnail. This includes the output filename.</param>
        /// <param name="height">Desired height of the thumbnail image</param>
        /// <param name="addSufix">If true, an extension is added to differentiate from the original image</param>
        /// <param name="sufix">The sufix to be be added in output filename, if not supplied, _thumb will be used.</param>
        /// <returns>True if the thumbnail is successfuly created, false otherwise</returns>
        public static string CreateThumbnailByHeight(string parentImageFilePath, string outputImageFilePath, int height, bool addSufix, string sufix)
        {
            // Trying to locate the original image file
            string parentImageFileFullPath = HttpContext.Current.Server.MapPath(parentImageFilePath);

            if (File.Exists(parentImageFileFullPath))
            {
                if (string.IsNullOrEmpty(sufix))
                    sufix = "_thumb";

                // Adding the sufix to the filename
                if (addSufix)
                    outputImageFilePath = outputImageFilePath.Insert(outputImageFilePath.IndexOf('.'), sufix);

                // Deleting if the file already exists.
                if (File.Exists(outputImageFilePath))
                    FileAccessUtility.DeleteFile(outputImageFilePath);

                // Loading the image from image file
                using (Image parentImage = Image.FromFile(parentImageFileFullPath))
                {
                    // Dynamically calculating the width of the thumbnail image according to ratio
                    int width = (int)(parentImage.Height * ((double)height / (double)parentImage.Height));

                    // Creating the thumbnail and saving it 
                    Image thumbnail = new Bitmap(width, height);
                    Graphics graphic = Graphics.FromImage(thumbnail);

                    graphic.InterpolationMode = InterpolationMode.HighQualityBicubic;
                    graphic.SmoothingMode = SmoothingMode.HighQuality;
                    graphic.PixelOffsetMode = PixelOffsetMode.HighQuality;
                    graphic.CompositingQuality = CompositingQuality.HighQuality;

                    graphic.DrawImage(parentImage, 0, 0, width, height);

                    if (parentImageFilePath.ToLower().EndsWith(".gif"))
                    {
                        using (thumbnail)
                        {
                            OctreeQuantizer quantizer = new OctreeQuantizer(255, 8);
                            using (Bitmap quantized = quantizer.Quantize(thumbnail))
                            {
                                using (FileStream outputStream = new FileStream(HttpContext.Current.Server.MapPath(outputImageFilePath), FileMode.Create))
                                {
                                    quantized.Save(outputStream, ImageFormat.Gif);
                                }
                            }
                        }
                    }
                    else if (parentImageFilePath.ToLower().EndsWith(".jpg"))
                    {
                        ImageCodecInfo[] info = ImageCodecInfo.GetImageEncoders();
                        EncoderParameters encoderParameters;
                        encoderParameters = new EncoderParameters(1);
                        encoderParameters.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
                        using (FileStream outputStream = new FileStream(HttpContext.Current.Server.MapPath(outputImageFilePath), FileMode.Create))
                        {
                            thumbnail.Save(outputStream, info[1], encoderParameters);
                        }
                    }
                    else
                    {
                        Image thumbnailImage = parentImage.GetThumbnailImage(width, height, null, IntPtr.Zero);
                        thumbnailImage.Save(HttpContext.Current.Server.MapPath(outputImageFilePath), parentImage.RawFormat);
                    }
                }
                return outputImageFilePath;
            }
            else
                return null;
        }

        /// <summary>
        /// Rotates and flips an image and saves in the destination folder
        /// </summary>
        /// <param name="parentImageFilePath">Path of the original image. This is relative path from site root</param>
        /// <param name="outputImageFilePath">Path of the output image where to create the thumbnail. This includes the output filename.</param>
        /// <param name="ratioPercent">Ratio in percentage in which to set the width and height of the new image</param>
        /// <param name="angleOrDirection">Angle of rotation, or filp direction</param>
        /// <param name="addSufix">If true, an extension is added to differentiate from the original image</param>
        /// <param name="sufix">The sufix to be be added in output filename, if not supplied, _thumb will be used.</param>
        /// <returns>True if the rotated image is successfuly created, false otherwise</returns>
        public static string RotateOrFlip(string parentImageFilePath, string outputImageFilePath, int ratioPercent,
            RotateFlipType angleOrDirection, bool addSufix, string sufix)
        {
            // Trying to locate the original image file
            FileInfo parentImageFile = new FileInfo(HttpContext.Current.Server.MapPath(parentImageFilePath));
            if (parentImageFile.Exists)
            {
                if (string.IsNullOrEmpty(sufix))
                    sufix = "_thumb";

                // Adding the sufix to the filename
                if (addSufix)
                    outputImageFilePath = outputImageFilePath.Insert(outputImageFilePath.IndexOf('.'), sufix);

                // Deleting if the file already exists.
                if (File.Exists(outputImageFilePath))
                    FileAccessUtility.DeleteFile(outputImageFilePath);

                // Loading the image from image file
                using (Image parentImage = Image.FromFile(parentImageFile.FullName))
                {
                    // Calculating the width and height dynamically based
                    // on provided ratio
                    int width = (int)(parentImage.Width * ratioPercent / 100.0);
                    int height = (int)(parentImage.Height * ratioPercent / 100.0);

                    // Creating the thumbnail and saving it 
                    Image thumbnailImage = parentImage.GetThumbnailImage(width, height, null, IntPtr.Zero);
                    thumbnailImage.RotateFlip(angleOrDirection);
                    thumbnailImage.Save(HttpContext.Current.Server.MapPath(outputImageFilePath), parentImage.RawFormat);
                    return outputImageFilePath;
                }
            }
            else
                return null;
        }

        /// <summary>
        /// Saves the image in specified format. Useful for converting one type of image into other type of image
        /// </summary>
        /// <param name="parentImageFilePath">Path of the original image. This is relative path from site root</param>
        /// <param name="outputImageFilePath">Path of the folder where to create the new image</param>
        /// <param name="outputFormat">Format of the image file</param>
        /// <param name="sufix">user defined sufix to add in the new image</param>
        /// <returns>True if the new image is saved successfuly, false otherwise</returns>
        public static string SaveAs(string parentImageFilePath, string outputImageFilePath, ImageFormat outputFormat)
        {
            // Using a temporary memory buffer to save the image in different format
            using (MemoryStream tempBuffer = new MemoryStream())
            {
                string parentImageFileFullPath = HttpContext.Current.Server.MapPath(parentImageFilePath);

                if (File.Exists(parentImageFileFullPath))
                {
                    // Loading the image from image file
                    using (Bitmap parentImage = new Bitmap(parentImageFileFullPath))
                    {
                        // Converting the image type and saving in buffer
                        parentImage.Save(tempBuffer, outputFormat);
                        // Writing the buffer into file
                        using (FileStream fileStream = new FileStream(HttpContext.Current.Server.MapPath(outputImageFilePath)
                            , FileMode.Create, FileAccess.Write))
                        {
                            tempBuffer.WriteTo(fileStream);
                            tempBuffer.Close();
                            tempBuffer.Dispose();
                            parentImage.Dispose();
                        }
                    }
                    return outputImageFilePath;
                }
                else
                    return null;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="parentImageFilePath">Path of the original image. This is relative path from site root</param>
        /// <param name="outputImageFilePath">Path, where to create the thumbnail</param>
        /// <param name="left">Crop rectangle left pixel distance</param>
        /// <param name="top">Crop rectangle top pixel distance</param>
        /// <param name="width">Crop rectangle width</param>
        /// <param name="height">Crop rectangle height</param>
        /// <param name="addSufix">If true, a _crop extension is added to differentiate from the original image</param>
        /// <returns></returns>
        public static string CreateCrop(string parentImageFilePath, string outputImageFilePath, int left, int top,
            int width, int height, bool addSufix, string sufix)
        {
            // Trying to locate the original image file
            string parentImageFileFullPath = HttpContext.Current.Server.MapPath(parentImageFilePath);

            if (File.Exists(parentImageFileFullPath))
            {
                if (string.IsNullOrEmpty(sufix))
                    sufix = "_thumb";

                // Adding the sufix to the filename
                if (addSufix)
                    outputImageFilePath = (outputImageFilePath.Insert(outputImageFilePath.IndexOf('.'), sufix));

                // Deleting if the file already exists.
                if (File.Exists(outputImageFilePath))
                    FileAccessUtility.DeleteFile(outputImageFilePath);

                // Loading the image from image file
                using (Image parentImage = Image.FromFile(parentImageFileFullPath))
                {
                    // Creating a dummy image with the width and height specified,
                    // 4th parameter should be always IntPtr.Zero
                    Image thumbnailImage = parentImage.GetThumbnailImage(width, height, null, IntPtr.Zero);

                    // Creating the image with the defined rectangle and saving it in file
                    using (Graphics graphics = Graphics.FromImage(thumbnailImage))
                    {
                        graphics.DrawImage(parentImage, new Rectangle(0, 0, width, height), left, top, width,
                            height, GraphicsUnit.Pixel);

                        thumbnailImage.Save(HttpContext.Current.Server.MapPath(outputImageFilePath),
                            parentImage.RawFormat);
                    }
                }
                return outputImageFilePath;
            }
            else
                return null;
        }

        public static Size GetImageDimension(string imageFilePath)
        {
            Size dimension = new Size();
            // Trying to locate the original image file
            FileInfo imageFile = new FileInfo(HttpContext.Current.Server.MapPath(imageFilePath));
            if (imageFile.Exists)
            {
                // Loading the image from image file
                using (Image image = Image.FromFile(imageFile.FullName))
                {
                    dimension = image.Size;
                }
            }
            return dimension;
        }
    }
}
